﻿namespace com.stifel.ProjectMgmt
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Globalization;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;

    using com.stifel.Extensions.DateTimeExtensions;
    using com.stifel.Extensions.StringExtensions;
    using com.stifel.ProjectMgmtDao;

    [ToolboxItemAttribute( false )]
    public class ProjectCalendar : WebPart
    {
        #region Fields

        const string ALIGNCENTER = "center";
        const string ALIGNLEFT = "left";
        const string ALIGNRIGHT = "right";
        const string BACKGROUNDPOSITION = "background-position";
        const string BACKGROUNDPOSITIONTOP = "top";
        const string BACKGROUNDREPEAT = "background-repeat";
        const string BACKGROUNDREPEATX = "repeat-x";
        const string BLACK = "Black";
        const string BORDERCOLLAPSE = "collapse";
        const string BORDERCOLOR = "#d8d8d8";
        const int DAYWIDTHPERCENTAGE = 13;
        const string FONTWEIGHTBOLD = "bold";
        const string MMMDYY = "MMM d, yyyy";
        const string NA = "n/a";
        const string NBSP = "&nbsp;";
        const string ONMOUSEOUT = "onmouseout";
        const string ONMOUSEOVER = "onmouseover";
        const string OVERFLOWHIDDEN = "hidden !important";
        const string TABLELAYOUT = "table-layout";
        const string TABLELAYOUTFIXED = "fixed";
        const string TEXTOVERFLOWELLIPSIS = "ellipsis !important";
        const string VALIGNMIDDLE = "middle";
        const string VALIGNTOP = "top";
        const string WHITESPACENOWRAP = "nowrap !important";
        const string YYMMDD = "yyyy/MM/dd";

        int? _columnWidth;
        List<internalProject> _internalProjects;
        List<Legend> _legends;

        #endregion Fields

        #region Properties

        public int CalendarWidth
        {
            get;
            set;
        }

        [Bindable( true ),
        Category( "Appearance" ),
        Description( "Calendar month to display." )]
        public DateTime Date
        {
            get;
            set;
        }

        public new Font Font
        {
            get;set;
        }

        public List<StifelProject> Projects
        {
            get;
            set;
        }

        string backgroundImage
        {
            get
            {
                return "~/_layouts/com.stifel.ProjectMgmt/images/gradient64x642.png";
            }
        }

        string browser
        {
            get;
            set;
        }

        int columnWidth
        {
            get
            {
                if ( !_columnWidth.HasValue )
                    _columnWidth = CalendarWidth * DAYWIDTHPERCENTAGE;
                return _columnWidth.Value;
            }
        }

        string dayWidth
        {
            get
            {
                return string.Format( "{0}%", DAYWIDTHPERCENTAGE );
            }
        }

        List<internalProject> internalProjects
        {
            get
            {
                if ( _internalProjects == null )
                    _internalProjects = new List<internalProject>( );
                return _internalProjects;
            }
        }

        List<Legend> legends
        {
            get
            {
                if ( _legends == null )
                    _legends = new List<Legend>( );
                return _legends;
            }
            set
            {
                _legends = value;
            }
        }

        List<StifelProject> projects
        {
            get;
            set;
        }

        #endregion Properties

        #region Methods

        protected override void OnPreRender( EventArgs e )
        {
            base.OnPreRender( e );
            //if ( !base.Page.ClientScript.IsClientScriptBlockRegistered( typeof( ProjectCalendar ).Name ) )
            //    base.Page.ClientScript.RegisterStartupScript( typeof( ProjectCalendar ), typeof( ProjectCalendar ).Name, "<script language=\"javascript\" type=\"text/javascript\">function resizeTables(){document.getElementById('divcal').style.width = '1px';document.getElementById('divcal').style.width = document.getElementById('tblcal').clientWidth + 'px';}$(window).load(function() {resizeTables();});$(window).resize(function() {resizeTables();});</script>" );
            browser = Page.Request.Browser.Browser.ToLower( );
            initializeInternalStructures( );
        }

        protected override void Render( HtmlTextWriter writer )
        {
            base.Render( writer );

            writer.RenderBeginTag( HtmlTextWriterTag.Div );
            {
                writer.RenderBeginTag( HtmlTextWriterTag.Table );
                {
                    writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                    {
                        writer.AddStyleAttribute( HtmlTextWriterStyle.VerticalAlign, VALIGNTOP );
                        writer.RenderBeginTag( HtmlTextWriterTag.Td );
                        {
                            renderLeftPanel( writer );
                            writer.RenderEndTag( );
                        }
                        writer.AddStyleAttribute( HtmlTextWriterStyle.VerticalAlign, VALIGNTOP );
                        writer.RenderBeginTag( HtmlTextWriterTag.Td );
                        {
                            renderRightPanel( writer );
                            writer.RenderEndTag( );
                        }
                        writer.RenderEndTag( );
                    }
                    writer.RenderEndTag( );
                }
                writer.RenderEndTag( );
            }
        }

        void filterProjects( )
        {
            DateTime beginDate = Date.GetFirstDayOfCalendar( );
            DateTime endDate = Date.GetLastDayOfCalendar( );
            projects = ( from p in Projects
                         where ( p.StartDate.HasValue && p.StartDate.Value >= beginDate && p.StartDate.Value <= endDate ) ||
                             ( p.DueDate.HasValue && p.DueDate.Value >= beginDate && p.DueDate.Value <= endDate ) ||
                             ( p.StartDate.HasValue && p.DueDate.HasValue && p.StartDate.Value < beginDate && p.DueDate.Value > endDate )
                         select p ).ToList( );

            sortProjects( );
        }

        ColorScheme getColor( int j )
        {
            if ( j >= ColorSchemes.BaseColors.Count - 1 )
                j = 1;
            return ColorSchemes.BaseColors[ j ];
        }

        List<internalProject> getProjectsForWeek( DateTime date )
        {
            DateTime beginDate = date;
            DateTime endDate = date.AddDays( 7 );
            List<internalProject> l = ( from p in internalProjects
                                        where
                                            ( p.StartDate.HasValue && p.StartDate.Value >= beginDate && p.StartDate.Value <= endDate ) ||
                                            ( p.DueDate.HasValue && p.DueDate.Value >= beginDate && p.DueDate.Value <= endDate ) ||
                                            ( p.StartDate.HasValue && p.DueDate.HasValue && p.StartDate.Value < beginDate && p.DueDate.Value > endDate )
                                        select p ).ToList( );
            return l;
        }

        void initializeInternalStructures( )
        {
            filterProjects( );

            int i = 0;
            string currentSiteUrl = string.Empty;
            foreach ( StifelProject p in projects )
            {
                if ( string.IsNullOrEmpty( currentSiteUrl ) || !p.ParentSite.SiteUrl.Equals( currentSiteUrl ) )
                {
                    currentSiteUrl = p.ParentSite.SiteUrl;
                    i++;
                    legends.Add( new Legend
                    {
                        Color = getColor( i ),
                        Title = p.GetTeamNameAsString( )
                    } );
                }

                internalProject internalproject = new internalProject
                {
                    ProjectDescription = p.ProjectDescription.StripHTML( ).TrimNewLine( ),
                    DueDate = p.DueDate,
                    Group = p.GetTeamNameAsString( ),
                    GroupColor = getColor( i ),
                    TeamName = p.GetTeamNameAsString( ),
                    ProjectColor = getColor( i ),
                    Title = p.Title,
                    StartDate = p.StartDate
                };
                internalProjects.Add( internalproject );
            }
        }

        void renderEmptyRow( HtmlTextWriter writer )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Tr );
            {
                for ( int i = 0; i <= 8; i++ )
                {
                    writer.RenderBeginTag( HtmlTextWriterTag.Td );
                    {
                        writer.Write( "&nbsp;" );
                        writer.RenderEndTag( );
                    }
                }
                writer.RenderEndTag( );
            }
        }

        /// <summary>
        /// Legend area
        /// </summary>
        /// <param name="writer"></param>
        void renderLeftPanel( HtmlTextWriter writer )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Div );
            {
                writer.RenderBeginTag( HtmlTextWriterTag.H3 );
                {
                    writer.Write( "Legend" );
                    writer.RenderEndTag( );
                }
                writer.RenderBeginTag( HtmlTextWriterTag.Table );
                {
                    legends.Sort( ( a, b ) =>
                    {
                        return a.Title.CompareTo( b.Title );
                    } );
                    foreach ( Legend s in legends )
                    {
                        writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                        {
                            writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundImage, backgroundImage );
                            writer.AddStyleAttribute( BACKGROUNDPOSITION, BACKGROUNDPOSITIONTOP );
                            writer.AddStyleAttribute( BACKGROUNDREPEAT, BACKGROUNDREPEATX );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, s.Color.BackColor );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.Color, s.Color.ForeColor );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                writer.Write( string.Format( "&nbsp;&nbsp;{0}&nbsp;&nbsp;", s.Title ) );
                                writer.RenderEndTag( );
                            }
                            writer.RenderEndTag( );
                        }
                    }
                    writer.RenderEndTag( );
                }
                writer.RenderEndTag( );
            }
        }

        void renderProjectsForWeek( HtmlTextWriter writer, DateTime date )
        {
            List<internalProject> projects = getProjectsForWeek( date );
            projects.Sort( ( a, b ) =>
            {
                DateTime asd;
                if ( a.StartDate.HasValue )
                    asd = a.StartDate.Value;
                else
                    asd = a.DueDate.Value;
                DateTime bsd;
                if ( b.StartDate.HasValue )
                    bsd = b.StartDate.Value;
                else
                    bsd = b.DueDate.Value;
                string c = string.Format( "{0}\t{1}", asd.ToString( YYMMDD ), a.Title );
                string d = string.Format( "{0}\t{1}", bsd.ToString( YYMMDD ), b.Title );
                return c.CompareTo( d );
            } );
            if ( projects.Count <= 0 )
                renderEmptyRow( writer );
            else
            {
                foreach ( internalProject p in projects )
                {
                    DateTime startdate;
                    if ( p.StartDate.HasValue )
                        startdate = p.StartDate.Value;
                    else
                        startdate = p.DueDate.Value;
                    DateTime enddate = p.DueDate.Value;
                    if ( startdate < date )
                        startdate = date;
                    int i = 6 - ( int ) startdate.DayOfWeek;
                    if ( enddate > startdate.AddDays( i ) )
                        enddate = startdate.AddDays( i );
                    int startindex = ( ( int ) startdate.DayOfWeek ) + 1;
                    int endindex = ( ( int ) enddate.DayOfWeek ) + 1;
                    writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                    {
                        writeLeftPadding( writer, startindex );

                        int colspan = endindex - startindex + 1;
                        writer.AddAttribute( HtmlTextWriterAttribute.Colspan, colspan.ToString( ) );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.Width, string.Format( "{0}px", colspan * columnWidth ) );
                        writer.RenderBeginTag( HtmlTextWriterTag.Td );
                        {
                            writer.AddStyleAttribute( HtmlTextWriterStyle.Width, "100%" );
                            writer.RenderBeginTag( HtmlTextWriterTag.Table );
                            {
                                writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                                {
                                    writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                                    writer.AddAttribute( ONMOUSEOVER, tooltipShow( p ) );
                                    writer.AddAttribute( ONMOUSEOUT, tooltipHide( ) );
                                    writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundImage, backgroundImage );
                                    writer.AddStyleAttribute( BACKGROUNDPOSITION, BACKGROUNDPOSITIONTOP );
                                    writer.AddStyleAttribute( BACKGROUNDREPEAT, BACKGROUNDREPEATX );
                                    writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, p.ProjectColor.BackColor );
                                    writer.AddStyleAttribute( HtmlTextWriterStyle.Color, p.ProjectColor.ForeColor );
                                    writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                                    //writer.AddStyleAttribute( HtmlTextWriterStyle.Overflow, OVERFLOWHIDDEN );
                                    //writer.AddStyleAttribute( HtmlTextWriterStyle.WhiteSpace, WHITESPACENOWRAP );
                                    //writer.AddStyleAttribute( HtmlTextWriterStyle.TextOverflow, TEXTOVERFLOWELLIPSIS );
                                    writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, "8pt" );
                                    writer.RenderBeginTag( HtmlTextWriterTag.Td );
                                    {
                                        string t = p.Title.Trim( );
                                        int x = colspan * 15;
                                        if ( t.Length > x )
                                            t = string.Format( "{0}...", t.Substring( 0, x ) );

                                        writer.Write( t );
                                        writer.RenderEndTag( );
                                    }
                                    writer.RenderEndTag( );
                                }
                                writer.RenderEndTag( );
                            }
                            writer.RenderEndTag( );
                        }
                        writeRightPadding( writer, endindex );
                        writer.RenderEndTag( );
                    }
                }
                renderEmptyRow( writer );
            }
        }

        /// <summary>
        /// Calendar
        /// </summary>
        /// <param name="writer"></param>
        void renderRightPanel( HtmlTextWriter writer )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Div );
            {
                writer.AddStyleAttribute( HtmlTextWriterStyle.TextAlign, ALIGNCENTER );
                writer.RenderBeginTag( HtmlTextWriterTag.H3 );
                {
                    writer.Write( Date.ToString( "MMMM yyyy" ) );
                    writer.RenderEndTag( );
                }

                writer.AddAttribute( HtmlTextWriterAttribute.Width, string.Format( "{0}px", CalendarWidth ) );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderCollapse, BORDERCOLLAPSE );
                writer.AddStyleAttribute( TABLELAYOUT, TABLELAYOUTFIXED );
                writer.RenderBeginTag( HtmlTextWriterTag.Table );
                {
                    writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                    {
                        // week of year
                        writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                        writer.AddAttribute( HtmlTextWriterAttribute.Width, "9%" );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.ShadeColor );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.TextAlign, ALIGNCENTER );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.FontFamily, this.Font.Name );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, "8pt" );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.VerticalAlign, VALIGNTOP );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, ColorSchemes.ShadeColor );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.Color, BLACK );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                        writer.RenderBeginTag( HtmlTextWriterTag.Td );
                        {
                            writer.Write( "Week" );
                            writer.RenderEndTag( );
                        }

                        // day of week
                        for ( int i = 0; i <= 6; i++ )
                        {
                            DayOfWeek dayOfWeek = ( DayOfWeek ) Enum.Parse( typeof( DayOfWeek ), i.ToString( ) );
                            writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                            writer.AddAttribute( HtmlTextWriterAttribute.Width, dayWidth );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.ShadeColor );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.TextAlign, ALIGNCENTER );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.FontFamily, this.Font.Name );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, "8pt" );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.VerticalAlign, VALIGNTOP );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, ColorSchemes.ShadeColor );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.Color, BLACK );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                writer.Write( dayOfWeek.ToString( ) );
                                writer.RenderEndTag( );
                            }
                        }
                        writer.RenderEndTag( );
                    }
                    DateTime a = Date.GetFirstDayOfCalendar( );
                    DateTime b = Date.GetLastDayOfCalendar( );
                    for ( DateTime i = a; i <= b; i = i.AddDays( 7 ) )
                    {
                        writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                        {
                            DateTime k = i;
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.ShadeColor );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.TextAlign, ALIGNCENTER );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.VerticalAlign, VALIGNTOP );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, ColorSchemes.ShadeColor );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, "8pt" );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                writer.AddStyleAttribute( HtmlTextWriterStyle.FontWeight, FONTWEIGHTBOLD );
                                writer.RenderBeginTag( HtmlTextWriterTag.Div );
                                {
                                    writer.Write( k.GetWeekOfYear( ) );
                                    writer.RenderEndTag( );
                                }
                                writer.RenderEndTag( );
                            }
                            for ( int j = 0; j <= 6; j++ )
                            {
                                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.ShadeColor );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.TextAlign, ALIGNLEFT );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.VerticalAlign, VALIGNTOP );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, ColorSchemes.ShadeColor );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, "8pt" );
                                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                                {
                                    writer.Write( k.Day );
                                    writer.RenderEndTag( );
                                }
                                k = k.AddDays( 1 );
                            }
                            writer.RenderEndTag( );
                        }
                        renderProjectsForWeek( writer, i );
                    }
                    writer.RenderEndTag( );
                }
                writer.RenderEndTag( );
            }
        }

        void sortProjects( )
        {
            projects.Sort( ( a, b ) =>
            {
                string c = string.Format( "{0}\t{1}", a.GetTeamNameAsString( ), a.Title );
                string d = string.Format( "{0}\t{1}", b.GetTeamNameAsString( ), b.Title );
                return c.CompareTo( d );
            } );
        }

        string tooltipHide( )
        {
            return "tooltip.hide();";
        }

        string tooltipShow( internalProject p )
        {
            return string.Format( "tooltip.show('{0}');", p.ToolTip );
        }

        void writeLeftPadding( HtmlTextWriter writer, int startindex )
        {
            for ( int i = 0; i < startindex; i++ )
            {
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    writer.Write( "&nbsp;" );
                    writer.RenderEndTag( );
                }
            }
        }

        void writeRightPadding( HtmlTextWriter writer, int endindex )
        {
            for ( int i = endindex + 1; i < 8; i++ )
            {
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    writer.Write( "&nbsp;" );
                    writer.RenderEndTag( );
                }
            }
        }

        #endregion Methods

        #region Nested Types

        class Legend
        {
            #region Properties

            public ColorScheme Color
            {
                get;
                set;
            }

            public string Title
            {
                get;
                set;
            }

            #endregion Properties
        }

        #endregion Nested Types
    }
}